/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufc.si.tcc.qmusic.automatoImp;

import br.ufc.si.tcc.qmusic.interfaces.IAcorde;
import br.ufc.si.tcc.qmusic.model.Nota;
import br.ufc.si.tcc.qmusic.model.Tetrade;
import br.ufc.si.tcc.qmusic.model.Triade;
import br.ufc.si.tcc.qmusic.properties.Properties;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Lucas Ismaily
 */
public class AutomatoImp {

    private boolean mesmoTempo(Triade t) {

        if (t.empty()) {
            return false;
        }

        if (t.getTonica().getDeltaTimeInicial() == t.getQuinta().getDeltaTimeInicial() && t.getQuinta().getDeltaTimeInicial() == t.getTerca().getDeltaTimeInicial()) {
            return true;
        }
        return false;
    }

    private boolean mesmoTempo(Tetrade te) {

        if (te.empty()) {
            return false;
        }
        if (te.getTriade().getTonica().getDeltaTimeInicial() == te.getTriade().getQuinta().getDeltaTimeInicial()
                && te.getTriade().getQuinta().getDeltaTimeInicial() == te.getTriade().getTerca().getDeltaTimeInicial()
                && te.getSetima().getDeltaTimeInicial() == te.getTriade().getTerca().getDeltaTimeInicial()) {
            return true;
        }
        return false;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Triades Maiores
     */
    public List<Triade> reconhecerTriadesMaiores(ArrayList<Nota> notas) {
        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;
        while (i < (notas.size())) {
            Triade t = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            }
            if (t != null && t.isTriadeMaior() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_MAIOR);
                triades.add(t);
                i += 3;
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Triades Menores
     */
    public List<Triade> reconhecerTriadesMenores(ArrayList<Nota> notas) {

        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;

        while (i < (notas.size())) {
            Triade t = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            }
            if (t != null && t.isTriadeMenor() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_MENOR);
                triades.add(t);
                i += 3;
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Triades Aumentadas
     */
    public List<Triade> reconhecerTriadesAumentada(ArrayList<Nota> notas) {
        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;

        while (i < (notas.size())) {
            Triade t = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            }
            if (t != null && t.isTriadeAumentada() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_AUMENTADA);
                triades.add(t);
                i += 3;
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Triades Diminutas
     */
    public List<Triade> reconhecerTriadesDiminuta(ArrayList<Nota> notas) {

        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;

        while (i < (notas.size())) {
            Triade t = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            }
            if (t != null && t.isTriadeDiminuta() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_DIMINUTA);
                triades.add(t);
                i += 3;
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Triades Enarmônicas,
     * caso o autômato reconheça algum acorde enarmônico, iremos sugerir uma
     * opção de correção
     */
    public List<Triade> reconhecerTriadesEnarmonicas(ArrayList<Nota> notas) {
        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;

        while (i < (notas.size() - 3)) {
            Triade t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            if (t.isTriadeEnarmonica() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_ENARMONICA);
                triades.add(t);
                i += 3;
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Tetrades Menores
     */
    public List<Tetrade> reconhecerTetradesMenores(ArrayList<Nota> notas) {

        List<Tetrade> tetrades = new ArrayList<Tetrade>();
        int i = 0;
        while (i < notas.size()) {
            Triade t = null;
            Tetrade te = null;
            if (i < notas.size() - 3) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
                te = new Tetrade(new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2)), notas.get(i + 3));
            }
            if (te != null && te.isTetradeMenor() && mesmoTempo(te)) {
                if (t != null && t.isTriadeAumentada()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_AUMENTADA);
                } else if (t != null && t.isTriadeMaior()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_MAIOR);

                } else if (t != null && t.isTriadeMenor()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_MENOR);

                } else if (t != null && t.isTriadeDiminuta()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_DIMINUTA);
                }
                tetrades.add(te);
                i += 4;
            } else {
                te = new Tetrade();
                te.setTipo(Properties.NAO_FORMOU_TETRADE);
                te.setTriade(new Triade(notas.get(i), new Nota(""), new Nota("")));
                te.setSetima(new Nota(""));
                tetrades.add(te);
                i++;
            }
        }
        return tetrades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Tetrades Maiores
     */
    public List<Tetrade> reconhecerTetradesMaiores(ArrayList<Nota> notas) {

        List<Tetrade> tetrades = new ArrayList<Tetrade>();
        int i = 0;
        while (i < notas.size()) {
            Triade t = null;
            Tetrade te = null;
            if (i < notas.size() - 3) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
                te = new Tetrade(new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2)), notas.get(i + 3));
            }
            if (te != null && te.isTetradeMaior() && mesmoTempo(te)) {
                if (t != null && t.isTriadeAumentada()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_AUMENTADA);
                } else if (t != null && t.isTriadeMaior()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MAIOR);

                } else if (t != null && t.isTriadeMenor()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MENOR);

                } else if (t != null && t.isTriadeDiminuta()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_DIMINUTA);
                }
                tetrades.add(te);
                i += 4;
            } else {
                te = new Tetrade();
                te.setTipo(Properties.NAO_FORMOU_TETRADE);
                te.setTriade(new Triade(notas.get(i), new Nota(""), new Nota("")));
                te.setSetima(new Nota(""));
                tetrades.add(te);
                i++;
            }
        }
        return tetrades;
    }

    /*
     * Implementação de um Autômato que reconhece apenas as Tetrades Maiores
     */
    public List<Tetrade> reconhecerTetradesEnarmonicas(ArrayList<Nota> notas) {
        List<Tetrade> tetrades = new ArrayList<Tetrade>();
        int i = 0;

        while (i < (notas.size())) {

            Triade t = null;
            Tetrade te = null;
            if (i < (notas.size() - 3)) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
                te = new Tetrade(new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2)), notas.get(i + 3));
            }
            if (te != null && te.isTetradeEnarmonica() && mesmoTempo(te)) {
                t.setTipo(Properties.TETRADE_ENARMONICA);
                tetrades.add(te);
                i += 4;
            } else {
                te = new Tetrade();
                te.setTipo(Properties.NAO_FORMOU_TETRADE);
                te.setTriade(new Triade(notas.get(i), new Nota(""), new Nota("")));
                te.setSetima(new Nota(""));
                tetrades.add(te);
                i++;
            }
        }
        return tetrades;
    }

    /*
     * Implementação do Autômato que reconheçe Triades e Tetrades de uma música
     */
    public List<IAcorde> reconhecerTriadesTetrades(ArrayList<Nota> notas) {


        if (notas == null || notas.isEmpty()) {
            return null;
        }
        List<IAcorde> acordes = new ArrayList<IAcorde>();
        int i = 0;
        while (i < notas.size()) {
            Triade t = null;
            Tetrade te = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
            }
            if (i < notas.size() - 3) {
                te = new Tetrade(new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2)), notas.get(i + 3));
            }

            if (te != null && te.isTetradeMaior() && mesmoTempo(te)) {
                if (t.isTriadeAumentada()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_AUMENTADA);
                }
                if (t.isTriadeMaior()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MAIOR);
                }
                if (t.isTriadeMenor()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MENOR);
                }
                if (t.isTriadeDiminuta()) {
                    te.setTipo(Properties.TETRADE_MAIOR_TRIADE_DIMINUTA);
                }
                acordes.add(te);
                i += 4;
            } else if (te != null && te.isTetradeMenor() && mesmoTempo(te)) {
                if (t.isTriadeAumentada()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_AUMENTADA);
                }
                if (t.isTriadeMaior()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_MAIOR);
                }
                if (t.isTriadeMenor()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_MENOR);
                }
                if (t.isTriadeDiminuta()) {
                    te.setTipo(Properties.TETRADE_MENOR_TRIADE_DIMINUTA);
                }
                i += 4;
                acordes.add(te);
            } else if (te != null && te.isTetradeEnarmonica() && mesmoTempo(te)) {
                te.setTipo(Properties.TETRADE_ENARMONICA);
                acordes.add(te);
                i += 4;
            } else if (t != null && t.isTriadeMaior() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_MAIOR);
                acordes.add(t);
                i += 3;
            } else if (t != null && t.isTriadeMenor() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_MENOR);
                acordes.add(t);
                i += 3;
            } else if (t != null && t.isTriadeAumentada() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_AUMENTADA);
                acordes.add(t);
                i += 3;
            } else if (t != null && t.isTriadeDiminuta() && mesmoTempo(t)) {
                t.setTipo(Properties.TRIADE_DIMINUTA);
                acordes.add(t);
                i += 3;
            } else if (t != null && t.isTriadeEnarmonica() && mesmoTempo(te)) {
                t.setTipo(Properties.TRIADE_ENARMONICA);
                acordes.add(t);
                i += 3;
            } else {
                te = new Tetrade(new Triade(notas.get(i), null, null), new Nota(""));
                te.setTipo(Properties.NAO_FORMOU_TRIADE_NEM_TETRADE);
                acordes.add(te);
                i++;
            }
        }
        return acordes;
    }

    /*
     * Implementação do Autômato que reconhece Triades
     */
    public List<Triade> reconhecerTodasTriades(ArrayList<Nota> notas) {

        if (notas == null || notas.isEmpty()) {
            return null;
        }
        List<Triade> triades = new ArrayList<Triade>();
        int i = 0;

        while (i < (notas.size())) {
            Triade t = null;
            if (i < notas.size() - 2) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));

                if (t != null && t.isTriadeMaior() && mesmoTempo(t)) {
                    t.setTipo(Properties.TRIADE_MAIOR);
                    triades.add(t);
                    i += 3;
                } else if (t != null && t.isTriadeMenor() && mesmoTempo(t)) {
                    t.setTipo(Properties.TRIADE_MENOR);
                    triades.add(t);
                    i += 3;
                } else if (t != null && t.isTriadeDiminuta() && mesmoTempo(t)) {
                    t.setTipo(Properties.TRIADE_DIMINUTA);
                    triades.add(t);
                    i += 3;

                } else if (t != null && t.isTriadeAumentada() && mesmoTempo(t)) {
                    t.setTipo(Properties.TRIADE_AUMENTADA);
                    triades.add(t);
                    i += 3;
                } else if (t.isTriadeEnarmonica() && mesmoTempo(t)) {
                    t.setTipo(Properties.TRIADE_ENARMONICA);
                    triades.add(t);
                    i += 3;
                } else {
                    t.setTipo(Properties.NAO_FORMOU_TRIADE);
                    t.setTonica(notas.get(i));
                    t.setTerca(new Nota(""));
                    t.setQuinta(new Nota(""));
                    triades.add(t);
                    i++;
                }
            } else {
                t = new Triade();
                t.setTipo(Properties.NAO_FORMOU_TRIADE);
                t.setTonica(notas.get(i));
                t.setTerca(new Nota(""));
                t.setQuinta(new Nota(""));
                triades.add(t);
                i++;
            }
        }
        return triades;
    }
    /*
     * Implementação do Autômato que reconheçe Triades e Tetrades de uma música
     */

    public List<Tetrade> reconhecerTodasTetrades(ArrayList<Nota> notas) {

        if (notas == null || notas.isEmpty()) {
            return null;
        }

        List<Tetrade> acordes = new ArrayList<Tetrade>();
        int i = 0;
        int tam = notas.size();
        while (i < tam) {
            Triade t = null;
            Tetrade te = null;
            if (i < tam - 3) {
                t = new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2));
                te = new Tetrade(new Triade(notas.get(i), notas.get(i + 1), notas.get(i + 2)), notas.get(i + 3));
                if (te != null && (te.isTetradeMaior() && mesmoTempo(te))) {
                    if (t.isTriadeAumentada()) {
                        te.setTipo(Properties.TETRADE_MAIOR_TRIADE_AUMENTADA);
                    }
                    if (t.isTriadeMaior()) {
                        te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MAIOR);
                    }
                    if (t.isTriadeMenor()) {
                        te.setTipo(Properties.TETRADE_MAIOR_TRIADE_MENOR);
                    }
                    if (t.isTriadeDiminuta()) {
                        te.setTipo(Properties.TETRADE_MAIOR_TRIADE_DIMINUTA);
                    }
                    acordes.add(te);
                    i += 4;
                } else if (te != null && (te.isTetradeMenor() && mesmoTempo(te))) {
                    if (t.isTriadeAumentada()) {
                        te.setTipo(Properties.TETRADE_MENOR_TRIADE_AUMENTADA);
                    }
                    if (t.isTriadeMaior()) {
                        te.setTipo(Properties.TETRADE_MENOR_TRIADE_MAIOR);
                    }
                    if (t.isTriadeMenor()) {
                        te.setTipo(Properties.TETRADE_MENOR_TRIADE_MENOR);
                    }
                    if (t.isTriadeDiminuta()) {
                        te.setTipo(Properties.TETRADE_MENOR_TRIADE_DIMINUTA);
                    }
                    i += 4;
                    acordes.add(te);
                } else if (te != null && te.isTetradeEnarmonica() && mesmoTempo(te)) {
                    te.setTipo(Properties.TETRADE_ENARMONICA);
                    acordes.add(te);
                    i += 4;
                } else {
                    te = new Tetrade();
                    te.setTipo(Properties.NAO_FORMOU_TETRADE);
                    te.setTriade(new Triade(notas.get(i),new Nota(""),new Nota("")));
                    te.setSetima(new Nota(""));
                    acordes.add(te);
                    i++;
                }


            } else {
                te = new Tetrade();
                te.setTipo(Properties.NAO_FORMOU_TETRADE);
                te.setTriade(new Triade(notas.get(i), new Nota(""), new Nota("")));
                te.setSetima(new Nota(""));
                acordes.add(te);
                i++;
            }
        }
        return acordes;
    }
}
